package com.ensentec.Lib;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Created by ztlchina on 17-7-28.
 * 电子秤类
 */

public class ElecScale {
    private static ElecScale ourInstance;// = new ElecScale();
    private String TAG = ElecScale.class.getSimpleName();
    private SerialPort mSerialPort;
    private OutputStream mOutputStream;
    private InputStream mInputStream;
    private ReadThread mReadThread;
    private String path = "/dev/ttySAC2";
    private int baudrate = 19200;
    private int stop = 1;
    private int bits = 8;
    private byte even = 0x02;   //偶校验
    private int block = 0;


    private OnGetScaleVale onGetScaleValue = null;
    private volatile boolean isStop = false;

    private  double value = 0.0;

    /* 自由协议电子秤 */
    private  byte[] mBuffer       = {0x3B, 0x02, 0x45, 0x45, 0x45, 0x0A};
    private  byte[] mBuffer_read  = {0x3B, 0x02, 0x45, 0x45, 0x45, 0x0A};         //读取测量值
    private  byte[] mBuffer_gross = {0x3B, 0x02, 0x45, 0x45, 0x45, 0x0A};        //切换到毛重输出状态
    private  byte[] mBuffer_tare  = {0x3B, 0x02, 0x45, 0x45, 0x45, 0x0A};         //切换到去皮输出
    /* 电子秤modbus协议 */
    private  byte[] mCMDGetValue  = {0x1F, 0x03, 0x00, 0x2A, 0x00, 0x01, (byte)0xA6, 0x7C };      //称重
    private  byte[] mCMDClear     = {0x1F, 0x06, 0x00, 0x24, 0x00, 0x00, (byte)0xCA, 0x7F };      //去皮
    private  boolean m_NetWeight = false;
    private  boolean m_StartRead = false;
    private  boolean m_StartFlag = false;

    public void Scale_NetWeight()
    {
        m_NetWeight = true;
        m_StartRead = false;
        isStop = false;

        if (mReadThread.isAlive() == false)
        {
            mReadThread.start();
        }
    }

    public  void Scale_StartRead()
    {
        m_StartRead = true;
        isStop = false;

        if (mReadThread.isAlive() == false)
        {
            mReadThread.start();
        }
    }

    public  void Scale_StopRead()
    {
        isStop = true;
        m_StartRead = false;
        mReadThread.interrupt();
    }

    public static ElecScale getInstance() {
        if (null == ourInstance)
        {
            ourInstance = new ElecScale();
            ourInstance.onCreate();
        }
        return ourInstance;
    }

    public interface OnGetScaleVale {
        public void onGetScaleValue(double value);
    }

    public void setOnDataReceiveListener(
            OnGetScaleVale getScaleValue) {
        onGetScaleValue = getScaleValue;
    }

    /**
     * 初始化串口信息
     */
    public void onCreate() {
        try {
            //SerialPort(File device, int baudrate, int nbits, byte nEvent, int stop, int block)
            mSerialPort = new SerialPort(new File(path), baudrate, bits, even, stop, block);
            mOutputStream = mSerialPort.getOutputStream();
            mInputStream = mSerialPort.getInputStream();

            mReadThread = new ReadThread();

            isStop = false;
            m_StartFlag = false;
            //mReadThread.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public  boolean GetRunStatus()
    {
        return m_StartFlag;
    }

    /**
     * 向串口发送16进制
     * @param mBuffer
     * @return 发送的结果
     */
    public boolean sendBuffer(byte[] mBuffer) {
        boolean result = true;
//        String tail = "\r\n";
//        byte[] tailBuffer = tail.getBytes();
//        byte[] mBufferTemp = new byte[mBuffer.length+tailBuffer.length];
//        System.arraycopy(mBuffer, 0, mBufferTemp, 0, mBuffer.length);
//        System.arraycopy(tailBuffer, 0, mBufferTemp, mBuffer.length, tailBuffer.length);
        try {
            if (mOutputStream != null) {
                //mOutputStream.write(mBufferTemp);
                mOutputStream.write(mBuffer);
            } else {
                result = false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }


    public static int getCrc16(byte[] arr_buff, int len) {
        //int len = arr_buff.length;

        //预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
        int crc = 0xFFFF;
        int i, j;
        for (i = 0; i < len; i++) {
            //把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
            crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff[i] & 0xFF));
            for (j = 0; j < 8; j++) {
                //把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
                if ((crc & 0x0001) > 0) {
                    //如果移出位为 1, CRC寄存器与多项式A001进行异或
                    crc = crc >> 1;
                    crc = crc ^ 0xA001;
                } else
                    //如果移出位为 0,再次右移一位
                    crc = crc >> 1;
            }
        }
        return crc;
    }

    private class ReadThread extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isStop && !isInterrupted()) {
                m_StartFlag = true;
                int size;
                try {
                    //首先拉高485IO口
//                    IOCtrl.getInstance().IO485Write();
                    Thread.sleep(1);
                    if (m_NetWeight) {
                        m_NetWeight = false;
                        sendBuffer(mCMDClear);
                    } else if (m_StartRead) {
                        sendBuffer(mCMDGetValue);
                    } else {
                        m_StartFlag = false;
                        return;
                    }

                    if (mInputStream == null) {
                        m_StartFlag = false;
                        return;
                    }

                    Thread.sleep(3);      //sleep 100ms
//                    IOCtrl.getInstance().IO485Read();
                    Thread.sleep(300);      //sleep 100ms

                    byte[] buffer = new byte[128];
                    size = mInputStream.read(buffer);
                    if (size > 6) {
                        /*

                        R_CWV
                        输       入：0x1F 0x03 0x00 0x2A 0x00 0x01 0xA6 0x7C
                        功       能：读取数字模块当前测量值，绝对值小于32000的测量值
                        回 答 信 息：0x1F 0x03 0x02 0xXX 0xYY 0xCC 0xDD
                                    xxyy为十六进制称重值
                        例：发送：1F 03 00 2A 00 01 A6 7C
                            回复：1F 03 02 4E 02 25 FD      称重值4E02即10进制19970

                        地址编号为1F模块清零：
                        输入：1F 06 00 24 00 00 CA 7F
                        回复：1F 06 00 24 00 00 CA 7F

                        */

                        //Todo:解析数据;

                        if (buffer[0] == 0x1f/* && getCrc16(buffer, size) == 0*/) {
                            if (buffer[1] == 0x03) {
                                int g = (((int) (buffer[3]&0xff) << 8) & 0xff00) | (int) (buffer[4]&0xff) ;

                                value = g / 1000.0;

                                if (null != onGetScaleValue) {
                                    onGetScaleValue.onGetScaleValue(value);
                                }

                            } else if (buffer[1] == 0x06) {
                                //清零成功
                                m_StartRead = true;
                            }
                            else {


                            }
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    m_StartFlag = false;
                    return;
                }
            }
            m_StartFlag = false;
        }
    }

    /**
     * 关闭串口
     */
    public void closeSerialPort() {
        isStop = true;
        if (mReadThread != null) {
            mReadThread.interrupt();
        }
        if (mSerialPort != null) {
            mSerialPort.close();
        }
    }
}
